import protobuf from 'protobufjs';
import fs from 'fs';
import { Adapter } from '../cli.js';

/**
 * @zh 生成 commander 参数定义
 * @en Generate commander parameter definitions
 */
export const genCommanderCode: Adapter = (
    filePath: string,
    messageName: string,
) => {
    const buf = fs.readFileSync(filePath, 'utf-8');
    const proto = protobuf.parse(buf, {
        alternateCommentMode: true,
    });
    const defaultCommandName = 'run';
    const template = proto.root.lookup(messageName)!;
    // @ts-ignore
    const { fields, nested } = template.toJSON({ keepComments: true });
    // console.log(fields);
    const importHeader = `/* automatically generated by proto-to-cli */
import { toInt, toFloat, toFile, toBoolean, HandleRepeated } from "proto-to-cli/dist/parser.js";
import { Command } from 'commander';
const run = new Command("${defaultCommandName}");
`;

    const shortCode = new Set();
    const params = `run` + createFlatDefine(fields).join('\n    ');

    function createFlatDefine(fields: any, parentKey = ''): string[] {
        return Object.entries<any>(fields).flatMap(([key, value]): string[] => {
            let isOption = value.options?.proto3_optional ?? false;
            if (parentKey) isOption = true;
            const comment = value.comment ?? '';
            const defaultValue = null;
            if (nested && Object.keys(nested).includes(value.type)) {
                // console.log(value.type);
                return createFlatDefine(
                    nested[value.type].fields,
                    key + '.',
                ) as string[];
            }
            let parser;
            let placeholder = ` <${value.type}>`;
            if (value.type.startsWith('int')) {
                parser = 'toInt';
            } else if (value.type.startsWith('float')) {
                parser = 'toFloat';
            } else if (value.type.startsWith('bytes')) {
                parser = 'toFile';
            } else if (value.type === 'bool') {
                parser = 'toBoolean';
            }
            if (value.rule === 'repeated' && parser) {
                parser = `HandleRepeated(${parser})`;
                isOption = true;
            }
            const longName = parentKey + key;
            let mayShortName = '';
            if (!parentKey && !shortCode.has(longName[0])) {
                mayShortName = '-' + longName[0] + ',';
                shortCode.add(longName[0]);
            }
            return [
                `.${
                    isOption ? 'option' : 'requiredOption'
                }('${mayShortName}--${longName}${placeholder}',"${comment}"${
                    parser ? ',' + parser : ''
                }${defaultValue ? ',' + defaultValue : ''})`,
            ];
        });
    }
    return (
        importHeader +
        params +
        `\nexport const getCliParams = (argv: string[], extraFn?: (cm: Command, run: Command) => void) => {
    const program = new Command();
    program.addCommand(run, { isDefault: true });
    extraFn && extraFn(program, run);
    return program.parse(argv);
};`
    );
};
